package com.hse.network;

import com.hse.application.ApplicationLayerException;
import com.hse.application.ApplicationMacStackLayer;
import com.hse.network.exceptions.NetworkException;
import com.meshnetics.gb.stack.mac.type.PANDescriptor;

public class EndDevice implements IEndDevice {

    private ApplicationMacStackLayer mac;
    private State state;
    private Short panId;
    private Short address;

    private enum State {
        Ready,
        Connected,
    }

    public EndDevice(String portName, long macAddress) throws InstantiationException {
        mac = new ApplicationMacStackLayer(portName);
        try {
            mac.init(macAddress);
        } catch (ApplicationLayerException e) {
            throw new InstantiationException(e.toString());
        }
        state = State.Ready;
    }

    public void connect(Short panId) throws NetworkException {
        try {
            address = mac.connect(panId);
        } catch (ApplicationLayerException e) {
            throw new NetworkException(e);
        }
        this.panId = panId;
        state = State.Connected;
    }

    public Network[] scan() throws NetworkException {
        if(state != State.Ready)
            throw new NetworkException("EndDevice is not ready. Current state: " + state);

        final PANDescriptor[] panDescriptors;
        try {
            panDescriptors = mac.scan();
        } catch (ApplicationLayerException e) {
            throw new NetworkException(e);
        }
        Network [] networks = new Network[panDescriptors.length];
        for(int i =0 ; i<panDescriptors.length; i++)
            networks[i] = new Network(panDescriptors[i].getCoordAddress().getPanId());
        return networks;
    }

    public byte[] recv() throws NetworkException {
        if(state != State.Connected)
            throw new NetworkException("EndDevice is not connected");
        return mac.recv(panId, ApplicationMacStackLayer.COORDINATOR_SHORT_ADDRESS, address);
    }

    public void send(byte[] data) throws NetworkException {
        if(state != State.Connected)
            throw new NetworkException("EndDevice is not connected");

        try {
            mac.send(panId, address, ApplicationMacStackLayer.COORDINATOR_SHORT_ADDRESS, data);
        } catch (ApplicationLayerException e) {
            throw new NetworkException(e);
        }
    }

    public boolean canRead() {
        return mac.canRead(panId, ApplicationMacStackLayer.COORDINATOR_SHORT_ADDRESS, address);
    }

    public void close() {
        mac.stop();
    }
}
